package io.modifier.basic.basic.kvwrapper.base

import android.content.Context
import android.content.SharedPreferences
import io.modifier.basic.basic.kvwrapper.core.KVStore
import io.modifier.basic.basic.kvwrapper.core.ObjectConverter
import io.modifier.basic.base.AppContext

/**
 * 以 [SharedPreferences] 为基础的 [KVStore] 的实现
 */
class SimpleKV(name: String) : KVStore {
    private val sp: SharedPreferences = AppContext.context.getSharedPreferences(name, Context.MODE_PRIVATE)
    private val editor: SharedPreferences.Editor = sp.edit()

    override fun putBoolean(key: String, value: Boolean?) {
        if (value == null) {
            editor.remove(key).apply()
        } else {
            editor.putBoolean(key, value).apply()
        }
    }

    // 基本类型，要实现不存在value时返回null, 需要先调用 contains 判断
    override fun getBoolean(key: String): Boolean? {
        return if (contains(key)) sp.getBoolean(key, false) else null
    }

    // 因此，如果有默认值，直接调用带默认值的方法会更有效率
    override fun getBoolean(key: String, defValue: Boolean): Boolean {
        return sp.getBoolean(key, defValue)
    }

    override fun putInt(key: String, value: Int?) {
        if (value == null) {
            editor.remove(key).apply()
        } else {
            editor.putInt(key, value).apply()
        }
    }

    override fun getInt(key: String): Int? {
        return if (contains(key)) sp.getInt(key, 0) else null
    }

    override fun getInt(key: String, defValue: Int): Int {
        return sp.getInt(key, defValue)
    }

    override fun putFloat(key: String, value: Float?) {
        if (value == null) {
            editor.remove(key).apply()
        } else {
            editor.putFloat(key, value).apply()
        }
    }

    override fun getFloat(key: String): Float? {
        return if (contains(key)) sp.getFloat(key, 0f) else null
    }

    override fun getFloat(key: String, defValue: Float): Float {
        return sp.getFloat(key, defValue)
    }

    override fun putLong(key: String, value: Long?) {
        if (value == null) {
            editor.remove(key).apply()
        } else {
            editor.putLong(key, value).apply()
        }
    }

    override fun getLong(key: String): Long? {
        return if (contains(key)) sp.getLong(key, 0L) else null
    }

    override fun getLong(key: String, defValue: Long): Long {
        return sp.getLong(key, defValue)
    }

    override fun putDouble(key: String, value: Double?) {
        if (value == null) {
            editor.remove(key).apply()
        } else {
            editor.putLong(key, java.lang.Double.doubleToRawLongBits(value))
        }
    }

    override fun getDouble(key: String): Double? {
        return if (contains(key)) getDouble(key, 0.0) else null
    }

    override fun getDouble(key: String, defValue: Double): Double {
        return if (contains(key)) java.lang.Double.longBitsToDouble(
            getLong(key, 0L),
        ) else defValue
    }

    override fun putString(key: String, value: String?) {
        editor.putString(key, value).apply()
    }

    override fun getString(key: String): String? {
        return sp.getString(key, null)
    }

    override fun <T> putObject(key: String, value: T?, encoder: ObjectConverter<T>) {
        if (value == null) {
            remove(key)
        } else {
            kotlin.runCatching { putString(key, encoder.encode(value)) }
        }
    }

    override fun <T> getObject(key: String, encoder: ObjectConverter<T>): T? {
        val value = getString(key) ?: return null
        return kotlin.runCatching { encoder.decode(value) }.getOrNull()
    }

    private fun remove(key: String) {
        editor.remove(key).apply()
    }

    private fun contains(key: String): Boolean {
        return sp.contains(key)
    }
}
